//////////////////////////////////////////////////////////////////////////
//
// NO_Type.cpp
//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
#define NO_TAL_EXPORT

///////////////////////////////////////////////////////////////////////
#include <functional>
#include <typeinfo>

//////////////////////////////////////////////////////////////////////
typedef const type_info * CTypeInfoP;

///////////////////////////////////////////////////////////////////////
template <> struct std::less<CTypeInfoP> 
: public std::binary_function<CTypeInfoP, CTypeInfoP, bool> 
{
	bool operator()(CTypeInfoP x, CTypeInfoP y) const 
	{
		return ((x->before(*y))!=0);
	}
};

//////////////////////////////////////////////////////////////////////////
#include "NO_Externs.h"
#include "NO_Type.h"
#include "NO_TypeList.h"

//////////////////////////////////////////////////////////////////////////
//
// TypeHandler
//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// con/destruction
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
NO_TypeHandler::NO_TypeHandler():id(-1),toCtrl(0){}
NO_TypeHandler::~NO_TypeHandler()
{
	if(!toCtrl){return;}
	if(*toCtrl){(*toCtrl)->unRegisterHandler(*this);}
}

//////////////////////////////////////////////////////////////////////////
// modify
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
void NO_TypeHandler::setTypePtrToControl(NO_Type*& t)
{
	toCtrl = &t;
}

//////////////////////////////////////////////////////////////////////////
//
// NO_Type
//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
NO_Type::GlobalTypes NO_Type::globals;
NO_Type::InternTypes NO_Type::interns;

//////////////////////////////////////////////////////////////////////////
// con/destruction
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
NO_Type::NO_Type(NO_Plugin& plg):id(0),plugin(0),next(0)
{
	if(plugin){return;}
	plugin = &plg;
	plugin->addType(*this);
}

//////////////////////////////////////////////////////////////////////////
NO_Type::~NO_Type(void)
{
	TypeHandlers::iterator iter = typeHandlers.begin();
	TypeHandlers::iterator end = typeHandlers.end();
	while (iter!=end)
	{
		if(*iter){unRegisterHandler(**iter);}
		++iter;
	}
}

//////////////////////////////////////////////////////////////////////////
// retrieve
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
NO_UInt32		 NO_Type::getID(void)		const {return id;}
const NO_Plugin* NO_Type::getPlugin(void)	const {return plugin;}

//////////////////////////////////////////////////////////////////////////
NO_Boolean NO_Type::getIsValid(void) const
{
	if(!id)		{return 0;}
	if(!plugin)	{return 0;}
	return 1;	
}

//////////////////////////////////////////////////////////////////////////
// operator
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
bool NO_Type::operator ==(NO_Type const & rhs) const{return id==rhs.id;}
bool NO_Type::operator !=(NO_Type const & rhs) const{return id!=rhs.id;}

//////////////////////////////////////////////////////////////////////////
// modify static
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
NO_Boolean NO_Type::addGlobal(NO_Type& type)
{
	if(globals.find(type.getID())!=globals.end()){return 0;}
	globals.insert(&type);
	return 1;
}

//////////////////////////////////////////////////////////////////////////
NO_Boolean NO_Type::remGlobal(NO_Type& type)
{
	GlobalTypes::iterator iter = globals.find(type.getID());
	GlobalTypes::iterator end = globals.end();
	if(iter==end){return 0;}
	globals.erase(iter);
	return 1;
}

//////////////////////////////////////////////////////////////////////////
NO_Boolean NO_Type::addIntern(NO_Type& type)
{
	const std::type_info* rtti = &type.getRTTI();
	InternTypeIter iter = interns.find(rtti);
	InternTypeIter end = interns.end();
	if(iter!=end){return 0;}
	interns[rtti] = &type;
	return 1;
}

//////////////////////////////////////////////////////////////////////////
NO_Boolean NO_Type::remIntern(NO_Type& type)
{
	std::type_info const * rtti = &type.getRTTI();
	InternTypeIter iter = interns.find(rtti);
	InternTypeIter end = interns.end();
	if(iter==end){return 0;}
	interns.erase(rtti);
	return 1;
}

//////////////////////////////////////////////////////////////////////////
void NO_Type::registerHandler(NO_TypeHandler& handler)
{
	(*(handler.toCtrl)) = this;
	
	if(freeHandlers.empty())
	{
		handler.id = typeHandlers.size();
		typeHandlers.push_back(&handler);
		return;
	}
	
	NO_UInt32 id = freeHandlers.front();
	(*(typeHandlers.begin()+id)) = &handler;
	freeHandlers.pop_front();
}

//////////////////////////////////////////////////////////////////////////
void NO_Type::unRegisterHandler(NO_TypeHandler& handler)
{
	NO_UInt32 id = handler.id;
	if(typeHandlers.size()<=id){return;}
	
	TypeHandlers::iterator iter = typeHandlers.begin()+id;
	freeHandlers.push_back(id);
	(*(handler.toCtrl)) = 0;
	handler.id = -1;
	(*iter) = 0;
}

//////////////////////////////////////////////////////////////////////////
// retrieve static
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
NO_Type::InternTypeIter NO_Type::findIntern(type_info const & r)	{return interns.find(&r);}
NO_Type::GlobalTypeIter NO_Type::findGlobal(NO_UInt32 ID)			{return globals.find(ID);}
NO_Type::GlobalTypeIter NO_Type::findGlobal(const NO_Int8* name)	{return globals.find(noGetHash(name));}

//////////////////////////////////////////////////////////////////////////
NO_Type::InternTypeIter	NO_Type::beginIntern(void)	{return interns.begin();}
NO_Type::GlobalTypeIter	NO_Type::beginGlobal(void)	{return globals.begin();}

//////////////////////////////////////////////////////////////////////////
NO_Type::InternTypeIter	NO_Type::endIntern(void){return interns.end();}
NO_Type::GlobalTypeIter	NO_Type::endGlobal(void){return globals.end();}

//////////////////////////////////////////////////////////////////////////
NO_Type::InternTypeIter	NO_Type::nextIntern(InternTypeIter iter){return ++iter;}
NO_Type::GlobalTypeIter	NO_Type::nextGlobal(GlobalTypeIter iter){return ++iter;}

